'use strict'

const http = require('http')
const fs = require('fs')

function parseBodyHeaders(data){
    let headers = {}
    let dsplit = data.split('\r\n').filter(p => p.length > 0)

    let ind
    let k
    for(let d of dsplit){
        ind = d.indexOf(':')

        if(ind <= 0) continue

        k = d.substring(0, ind).toLowerCase()

        headers[k] = d.substring(ind+1).trim()
    }

    let cpd = headers['content-disposition']

    //按照;分割成数组，第一个元素form-data去掉
    let clist = cpd.split('; ').slice(1)

    let name, filename

    for(let a of clist){
        ind = a.indexOf('filename="')
        if(ind >= 0){
            filename = a.substring(ind+10, a.length-1)
        }else{
            name = a.substring(6, a.length-1)
        }
    }

    return{
        headers,
        name,
        filename
    }
}

/**
 * 
 * @param {Buffer} bodyData 原始的Body数据
 * @param {Object} reqHeaders request.headers
 */

function parseBody(bodyData, reqHeaders){

    //content-type: multipart/form-data; boundary=-----34294329
    let ctype = reqHeaders['content-type']

    //拿到分界线的boundary
    let bdy = ctype.substring(ctype.indexOf('=')+1)

    //数据中用于分割文件的分界线
    // bdy = `--${bdy}\r\n`

    let crlf_bdy = `\r\n--${bdy}`

    //从偏移bdy的长度开始查找下一个分界线的位置
    let data_end_index = bodyData.indexOf(crlf_bdy, crlf_bdy.length)

    //body消息数据中header部分最后的索引
    let header_end_index = bodyData.indexOf('\r\n\r\n', crlf_bdy.length)

    let header_data = bodyData.toString('utf8', crlf_bdy.length, header_end_index)

    //解析body数据中的消息头
    let hd = parseBodyHeaders(header_data)

    let fileinfo = {
        start: header_end_index+4,
        end: data_end_index,
    }
    fileinfo.length = fileinfo.end - fileinfo.start

    return{
        name: hd.name,
        filename: hd.filename,
        headers: hd.headers,
        start: fileinfo.start,
        end: fileinfo.end,
        length: fileinfo.length
    }
}

function parseExtName (filename){
    if(filename.length < 2) return ''

    let namesplit = filename.split('.').filter(p => p.length > 0)

    if(namesplit.length < 2) return '';

    return `.${namesplit[namesplit.length - 1]}`
}

let routerTable = {

GET:{
    '/upload':async(ctx) => {
        let stm = fs.createReadStream('./upload.html')
        stm.pipe(ctx.res)
        stm.on('end', ()=>{
            ctx.end()
        })
    }
},

POST:{
    '/upload':async(ctx) => {
        console.log(ctx.files)

        let finfo = ctx.files

        let filename = `${Date.now()}-` + `${parseInt(Math.random() * 100000) + 100000}` + parseExtName(finfo.filename)

        let fh = await fh.write(ctx.rawBody,
                                finfo.start,
                                finfo.length,
                                0)

        //关闭打开的文件
        fh.close()

        //返回写入的字节数，string或buffer类型，不能是其他类型
        ctx.end(`${fret.bytesWritten}`)
    }
}

}

/**----------- start server ------------ */

let serv = http.createServer()

serv.on('request', (request, response) => {
    let rm = routerTable[request.method]

    //根据？切分字符串
    let usplit = request.url.split('?')

    let pathname = usplit[0]
    let querystring = usplit[1] || ''

    if(!rm || !rm[pathname]){
        response.statusCode = 404
        response.end('page not found')
        return
    }

    //ctx is content, 创建请求上下文对象
    let ctx = {
        req: request,
        res: response,
        method: request.method,
        headers: request.headers,
        end: (data, encoding='utf8') => {
            response.end(data, encoding)
        },
        write: (data, encoding = 'utf8') => {
            response.write(data, encoding)
        },
        path: pathname,
        querystring: querystring,
        rawBody: null,
    }

    let bufferList = []
    let totalLength = 0

    if('PD'.indexOf(request.method[0]) >= 0){
        request.on('data', chunk => {
            totalLength += chunk.length
            bufferList.push(chunk)
        })
    }else{
        resquest.on('data', chunk => {
            response.statusCode = 400
            response.end()
        })
    }

    request.on('end', () => {
        if(bufferList.length > 0){
            ctx.rawBody = Buffer.concat(bufferList, totalLength)
            bufferList = []
        }

        let ctype = ctx.headers['content-type'] || ''

        if(ctx.rawBody && ctype.indexOf('multipart/form-data') === 0){
            ctx.files = parseBody(ctx.rawBody, ctx.headers)
        }

        rm[pathname](ctx)
    })


})

serv.listen(3456)